/**
 * 
 */
package org.kopsox.general.messages;

import java.util.Locale;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.Properties;
import java.util.ResourceBundle;
import java.util.concurrent.ConcurrentHashMap;

import org.kopsox.environment.proxy.KopsoxRegistry;

/**
 * The DynamicMessageLoader loads an text from an MessageBundle.<br>
 * MessageBundles can be defined in the kopsoxenvironment.properties.<br>
 * Each bundle which is specified in the kopsoxenvironemnt.properties must start with the word 'bundle', e.g.: 'bundle.nameofyourbundle'.<br>
 * If you want to define a specific locale for your bundle it must have following form: 'bundle.nameofyourbundle.locale'.<br>
 * You can also add MessageBundles at runtime with the registerBundle-Methods.<br>
 * 
 * @author Konrad Renner - 09.12.2010
 * @see ResourceBundle
 * @see Locale
 * @see KopsoxRegistry
 */
public final class DynamicMessageLoader {
	
	private final static String BUNDLE = "bundle";
	private final static String LOCALE = ".locale";
	
	private final Map<String, ResourceBundle> bundles;
	private volatile boolean notInitialized;
	
	public static final DynamicMessageLoader INSTANCE = new DynamicMessageLoader();

	private DynamicMessageLoader() {
		this.bundles = new ConcurrentHashMap<String, ResourceBundle>();
		this.notInitialized = true;
	}
	
	private synchronized void init() {
		if(this.notInitialized) {
			
			//Load the properties and an Load Each ResourceBundle
			Properties props = KopsoxRegistry.INSTANCE.getKopsoxProperties();
			
			for(Object propertyName:props.keySet()) {
				
				String name = propertyName.toString();
				
				if(name.startsWith(BUNDLE)) {
					String locale = null;
					String bundleName = null;
					
					if(name.endsWith(LOCALE)) {
						locale = props.getProperty(LOCALE);
						
						bundleName = name.substring(0, name.length()-LOCALE.length());
					}else {
						locale = props.getProperty(name+LOCALE);
						bundleName = name;
					}
					
					registerBundle(bundleName, locale, props.getProperty(bundleName));
				}
			}
			
			this.notInitialized = false;
		}
	}
	
	/**
	 * Registers an new Bundle to the MessageLoader.<r>
	 * The Locale String has to be in following form: language_country_variant, e.g.: de_AT
	 * 
	 * @param name
	 * @param locale - if it is null, the Locale.getDefault will be called
	 * @param pathToBundle
	 * @return boolean - true if the Bundle was registered
	 */
	public boolean registerBundle(String name,String locale,String pathToBundle) {
		if(this.bundles.containsKey(name)) {
			return false;
		}
		
		String[] localeStrings = locale==null?null:locale.split("_");
		Locale loc = null;
		if(localeStrings == null) {
			loc = Locale.getDefault();
		}else if(localeStrings.length >=3) {
			loc = new Locale(localeStrings[0],localeStrings[1],localeStrings[2]);
		}else if(localeStrings.length == 2) {
			loc = new Locale(localeStrings[0],localeStrings[1]);
		}else if(localeStrings.length == 1) {
			loc = new Locale(localeStrings[0]);
		}
		
		return registerBundle(name, loc, pathToBundle);
	}
	
	/**
	 * Registers an new Bundle to the MessageLoader
	 * 
	 * @param name
	 * @param locale - if it is null, the Locale.getDefault will be called
	 * @param pathToBundle
	 * @return boolean - true if the Bundle was registered
	 */
	public boolean registerBundle(String name,Locale locale,String pathToBundle) {
		if(bundles.containsKey(name)) {
			return false;
		}
		
		try {
			ResourceBundle bundle = ResourceBundle.getBundle(pathToBundle,locale==null?Locale.getDefault():locale);
			
			System.out.println(locale==null?Locale.getDefault():locale+";"+bundle.getLocale());
			
			this.bundles.put(name, bundle);
			
			return true;
		}catch(MissingResourceException e) {
			e.printStackTrace();
			
			return false;
		}
	}
	
	/**
	 * Gets an ResourceBundle with the specified name
	 * 
	 * @param name
	 * @return ResourceBundle
	 */
	public ResourceBundle getBundle(String name) {
		if(this.notInitialized) {
			init();
		}
		
		if(this.bundles.containsKey(name)) {
			return this.bundles.get(name);
		}
		
		return null;
	}
	
	/**
	 * Gets an Message from an ResourceBundle with the specified bundleName-Key
	 * 
	 * @param bundleName
	 * @param key
	 * @return String
	 */
	public String getMessage(String bundleName,String key) {
		
		ResourceBundle bundle = getBundle(bundleName);
		
		if(bundle == null) {
			return "No messages available";
		}
		
		try {
			return bundle.getString(key);
		} catch (MissingResourceException e) {
			StringBuilder builder = new StringBuilder();
			builder.append('!');
			builder.append(Locale.getDefault());
			builder.append(':');
			builder.append(key);
			builder.append('!');
			return builder.toString();
		}
	}
}
